package org.slf4j.impl;

import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MarkerIgnoringBase;
import org.slf4j.helpers.MessageFormatter;

import ar.fiuba.logger.FiubaLogger;
import ar.fiuba.logger.LogConfig;
import ar.fiuba.logger.Logger;
import ar.fiuba.logger.LogLevel;

public class FiubaLoggerAdapter extends MarkerIgnoringBase {

  private static final long serialVersionUID = 3888623147984815867L;
  Logger loggerImpl;

  public FiubaLoggerAdapter(String name) {
    FiubaLogger.create(name);

    loggerImpl = FiubaLogger.getLogger(name);
  }
  
  /**
   * Is the given log level currently enabled?
   *
   * @param logLevel is this level enabled?
   */
  protected boolean isLevelEnabled(LogLevel logLevel) {
    // log level are numerically ordered so can use simple numeric
    // comparison
    return loggerImpl.getThreshold().isNotWorseThan(logLevel);
  }

  /**
   * For formatted messages, first substitute arguments and then log.
   *
   * @param level
   * @param format
   * @param arg1
   * @param arg2
   */
  private void formatAndLog(LogLevel level, String format, Object arg1, Object arg2) {
    if (!isLevelEnabled(level)) {
      return;
    }
    FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
    loggerImpl.log(tp.getMessage(), level, tp.getThrowable());
  }

  /**
   * For formatted messages, first substitute arguments and then log.
   *
   * @param level
   * @param format
   * @param arguments a list of 3 ore more arguments
   */
  private void formatAndLog(LogLevel level, String format, Object... arguments) {
    if (!isLevelEnabled(level)) {
      return;
    }
    FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
    loggerImpl.log(tp.getMessage(), level, tp.getThrowable());
  }


  @Override
  public void debug(String format) {
    formatAndLog(LogLevel.DEBUG, format, null, null);
  }

  @Override
  public void debug(String format, Object param1) {
    formatAndLog(LogLevel.DEBUG, format, param1, null);
  }

  @Override
  public void debug(String format, Object param1, Object param2) {
    formatAndLog(LogLevel.DEBUG, format, param1, param2);
  }

  @Override
  public void debug(String format, Object... arguments) {
    formatAndLog(LogLevel.DEBUG, format, arguments);
  }

  @Override
  public void debug(String format, Throwable arg1) {
    this.loggerImpl.debug(format, arg1);
  }

  @Override
  public void error(String format) {
    formatAndLog(LogLevel.ERROR, format, null, null);
  }

  @Override
  public void error(String format, Object param1) {
    formatAndLog(LogLevel.ERROR, format, param1, null);
  }

  @Override
  public void error(String format, Object param1, Object param2) {
    formatAndLog(LogLevel.ERROR, format, param1, param2);
  }

  @Override
  public void error(String format, Object... arguments) {
    formatAndLog(LogLevel.ERROR, format, arguments);
  }

  @Override
  public void error(String arg0, Throwable arg1) {
    this.loggerImpl.error(arg0, arg1);
  }

  @Override
  public String getName() {
    return loggerImpl.getName();
  }

  @Override
  public void info(String format) {
    formatAndLog(LogLevel.INFO, format, null, null);
  }

  @Override
  public void info(String format, Object param1) {
    formatAndLog(LogLevel.INFO, format, param1, null);
  }

  @Override
  public void info(String format, Object param1, Object param2) {
    formatAndLog(LogLevel.INFO, format, param1, param2);
  }

  @Override
  public void info(String format, Object... arguments) {
    formatAndLog(LogLevel.INFO, format, arguments);
  }

  @Override
  public void info(String arg0, Throwable arg1) {
    this.loggerImpl.info(arg0, arg1);
  }

  @Override
  public boolean isDebugEnabled() {
    return isLevelEnabled(LogLevel.DEBUG);
  }

  @Override
  public boolean isErrorEnabled() {
    return isLevelEnabled(LogLevel.ERROR);
  }

  @Override
  public boolean isInfoEnabled() {
    return isLevelEnabled(LogLevel.INFO);
  }

  @Override
  public boolean isTraceEnabled() {
    return isLevelEnabled(LogLevel.TRACE);
  }

  @Override
  public boolean isWarnEnabled() {
    return isLevelEnabled(LogLevel.WARN);
  }

  @Override
  public void trace(String format) {
    formatAndLog(LogLevel.TRACE, format, null, null);
  }

  @Override
  public void trace(String format, Object param1) {
    formatAndLog(LogLevel.TRACE, format, param1, null);
  }

  @Override
  public void trace(String format, Object param1, Object param2) {
    formatAndLog(LogLevel.TRACE, format, param1, param2);
  }

  @Override
  public void trace(String format, Object... arguments) {
    formatAndLog(LogLevel.TRACE, format, arguments);
  }

  @Override
  public void trace(String format, Throwable ex) {
    this.loggerImpl.trace(format, ex);

  }

  @Override
  public void warn(String format) {
    formatAndLog(LogLevel.WARN, format, null, null);
  }

  @Override
  public void warn(String format, Object param1) {
    formatAndLog(LogLevel.WARN, format, param1, null);
  }

  @Override
  public void warn(String format, Object param1, Object param2) {
    formatAndLog(LogLevel.WARN, format, param1, param2);
  }

  @Override
  public void warn(String format, Object... arguments) {
    formatAndLog(LogLevel.WARN, format, arguments);
  }

  @Override
  public void warn(String arg0, Throwable arg1) {
    this.loggerImpl.warn(arg0, arg1);
  }

}
